import { Form, } from "antd"
import { renderFormElement } from "../index"
import { CSSProperties, useEffect, useState } from "react"
import { useComponentConfigStore } from "../../../editor/stores/component-config"
import { useComponentStore, } from "../../../editor/stores/components"
import { CodeEditor } from "../CodeEditor"
import { debounce } from "lodash-es"
import StyleToObject from 'style-to-object';

export function ComponentStyle() {
    const { componentConfigs } = useComponentConfigStore()
    const { curComponent, curComponentId, updateComponentStyles } = useComponentStore()
    const [css, setCss] = useState("");
    const [form] = Form.useForm()

    if (!curComponent || !curComponentId) return

    // 负责将 styles 数据渲染到表单和编辑器中 
    useEffect(() => {
        form.resetFields()
        const data = form.getFieldsValue()
        form.setFieldsValue({...data, ...curComponent.styles}) // 回显表单
        setCss(toCssStr(curComponent.styles!)) // 回显编辑器
   }, [curComponent])

    // 负责将 CSS 字符串转为 CSS 对象，然后更新到组件styles上（代码编辑器编辑时执行）
    const handleEditorChange = debounce((cssStr) => {
        // setCss(cssStr)
        // cssStr 只是字符串 ".comp { fontSize: 14px}"，需要解析成对象
        let cssObj: Record<string, any> = {}

        try {
            cssStr = cssStr.replace(/(\.?[^{+]+{)/, "") // 去掉 .comp {
                .replace(/}/, '') // 去掉 }
                .replace(/\/\*.*\*\//, "") // 去掉注释

            StyleToObject(cssStr, (name, value) => {
                // 如果存在连字符写法，改成驼峰写法
                cssObj[name.replace(/-\w/, (item) => item.toUpperCase().replace('-', ''))] = value;
            })

            // {...form.getFieldsValue(), ...css} 由于是覆盖更新，所以需要把 form 中的数据也加上
            updateComponentStyles(curComponentId, {...form.getFieldsValue(), ...cssObj}, true)
        } catch(e) {}
    }, 1000)

    // 把样式数据更新到组件styles上（修改表单组件数据时）
    const handleValueChange = debounce( (cssObj: CSSProperties) =>{
        if (curComponentId) {
            updateComponentStyles(curComponentId, cssObj)
        }
    }, 1000)

    // 将 component 里 styles 对象转为字符串（首次初始化和切换组件时执行）
    function toCssStr(cssObj: CSSProperties){
        let str = `.comp {\n`;

        for(let key in cssObj) {
            let value = cssObj[key]
            if (!value) continue

            // 如果 value 是数字，需要加上 px，这两个属性也是组件，所以需要特殊除里
            if (['width', 'height'].includes(key) && ! value.toString().endsWith('px')) {
                value += 'px'
            }

            // 将驼峰改回连字符
            key = key.replace(/[A-Z]/g, (item) => '-' + item.toLowerCase())

            str += `\t${key}: ${value};\n`
        }
        str += `\t\n}`
        return str;
    }

    return (
        <Form
            form={form}
            labelCol={{ span: 6 }}
            wrapperCol={{ span: 14 }}
            onValuesChange={handleValueChange}
        >
            {
                componentConfigs[curComponent.name]?.stylesSetter?.map((item, index) => (
                    <Form.Item key={item.name} label={item.label} name={item.name}>
                        {renderFormElement(item)}
                    </Form.Item>
                ))
            }
            <div className="h-[200px] border-[1px] border-[#ccc]">
                <CodeEditor value={css} onChange={handleEditorChange} />
            </div>
        </Form>
    )
}